package com.apobates.forum.toro.tuple.strategy;

import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 抽像的Pair异步策略
 * @param <L> 左对象类型
 * @param <R> 右对象类型
 * @param <U> 右对象查询函数参数的类型
 *
 * @author xiaofanku@live.cn
 * @since 20220517
 */
public abstract class AbstractPairFutureStrategy<L,R,U> extends AbstractTupleStrategy {
    private final int timeout;
    private final TimeUnit unit;
    private final static Logger logger = LoggerFactory.getLogger(AbstractPairFutureStrategy.class);

    public AbstractPairFutureStrategy(int timeout, TimeUnit unit) {
        this.timeout = timeout;
        this.unit = unit;
    }

    @Override
    protected String getSentinel() {
        return "PairFuture";
    }

    public AbstractPairFutureStrategy() {
        this.timeout = 1;
        this.unit = TimeUnit.SECONDS;
    }

    public int getTimeout() {
        return timeout;
    }

    public TimeUnit getUnit() {
        return unit;
    }

    /**
     * 返回聚合结果
     * @param lFuture 左对象的Future实例
     * @param rightFun 右对象查询函数
     * @param arguments 连接参数集合
     * @return
     */
    protected Pair<L, R> get(CompletableFuture<L> lFuture, Function<U, R> rightFun, Map<String, String> arguments){
        return lFuture.thenCompose((L leftObj) -> CompletableFuture.supplyAsync(() -> {
            Object selectRightVal = getBaseSelectVal(
                    leftObj,
                    arguments.get("rightAttr"),
                    arguments.get("rightAttrType"),
                    "右");
            R rightObj = null;
            try {
                rightObj = rightFun.apply((U)selectRightVal);
            }catch (Exception e) {
                logger.debug("[TS][PairFuture]获取对象时出现异常:"+e.getMessage());
            }
            return Pair.of(leftObj, rightObj);
        }).completeOnTimeout(null, this.timeout, this.unit)).orTimeout(this.timeout, this.unit).join();
    }

    /**
     * 返回聚合结果
     * @param lFuture 左对象的Future实例
     * @param rightFun 右对象查询函数
     * @param arguments 连接参数集合
     * @return
     */
    protected Pair<L, Collection<R>> getAny(CompletableFuture<L> lFuture, Function<U, Collection<R>> rightFun, Map<String, String> arguments) {
        return lFuture.thenCompose((L leftObj) -> CompletableFuture.supplyAsync(() -> {
            Object selectRightVal = getBaseSelectVal(
                    leftObj,
                    arguments.get("rightAttr"),
                    arguments.get("rightAttrType"),
                    "右");
            Collection<R> rightObj = new ArrayList<>();
            try {
                rightObj = rightFun.apply((U)selectRightVal);
            }catch (Exception e) {
                logger.debug("[TS][PairFuture]获取对象时出现异常:"+e.getMessage());
            }
            return Pair.of(leftObj, rightObj);
        }).completeOnTimeout(null, this.timeout, this.unit)).orTimeout(this.timeout, this.unit).join();
    }
}
